<template>
  <div class="pagewarp">
    <a-page-header
      :title="wiki_name"
      @back="() => $router.back()"
      style="padding: 0 0 10px 0"
    />
    <template v-if="state.showPage">
      <template v-if="!state.team_id">
        <div
          class="bg-white flex justify-center text-center py-40 flex-col"
          style="border-radius: 5px"
        >
          <div>
            <WarningFilled style="color: #faad14; font-size: 64px" />
          </div>
          <div class="fs-24 mt-20">此能力仅团队成员可用</div>
          <div class="mt-10 text-gray-6">当前身份: 个人</div>
          <a-row class="mt-20 flex justify-center">
            <a-button
              type="primary"
              style="border-radius: 6px"
              @click="changeTeamPopoverVisible(true)"
            >
              <template #icon><SwapOutlined /></template>
              切换团队
            </a-button>
            <a-button
              type="primary"
              class="ml-20"
              style="border-radius: 6px"
              @click="addTeamVisible = true"
            >
              <template #icon><PlusCircleOutlined /></template>
              创建团队
            </a-button>
          </a-row>
        </div>
      </template>
      <template v-else>
        <div class="flex justify-between">
          <div class="flex align-center flex-1">
            <div class="fs-16 bold-700 mr-20">知识库数据: {{ total }}组</div>
            <a-input
              placeholder="搜索相关问题和答案，回车确认"
              v-model:value="state.keywords"
              style="max-width: 240px"
              @keyup.enter="getWikiList"
            ></a-input>
          </div>
          <div>
            <a-button class="mr-10" @click="getWikiList">
              <template #icon>
                <SyncOutlined :style="{ fontSize: '12px' }" />
              </template>
            </a-button>
            <!-- <a-button class="mr-5">导出csv</a-button> -->
            <a-popover
              overlayClassName="popover-menu"
              v-model:visible="visible"
              placement="bottomRight"
              trigger="click"
            >
              <template #content>
                <div class="flex flex-col">
                  <a-button
                    type="text"
                    class="text-left"
                    @click="modalVisible = 'add'"
                    >手动输入</a-button
                  >
                  <a-button
                    type="text"
                    class="text-left"
                    @click="modalVisible = 'splitText'"
                    >文本/文件拆分</a-button
                  >
                  <a-button
                    type="text"
                    class="text-left"
                    @click="modalVisible = 'csvImport'"
                    >csv 问答对导入</a-button
                  >
                </div>
              </template>
              <a-button type="primary">导入</a-button>
            </a-popover>
          </div>
        </div>
        <div class="mt-20">
          <a-table
            :columns="columns"
            :data-source="wikiList"
            :loading="loading"
            :pagination="pagination"
            @change="handleTableChange"
            rowKey="id"
          >
            <template #customQuestion>
              <div class="flex align-center">
                <a-popover placement="bottom">
                  <template #content>
                    <div class="fs-12">
                      <p class="mb-0">
                        对话时，会将用户的问题和知识库的“匹配知识
                      </p>
                      <p class="mb-0">
                        点”进行比较，找到最相似的前 n 条记录，将这些
                      </p>
                      <p class="mb-0">记录的“匹配知识点”+"补充知识点”作为</p>
                      <p>chatgpt 的系统提示词。</p>
                    </div>
                  </template>
                  <QuestionCircleOutlined />
                </a-popover>
                <div class="ml-5">匹配的知识点</div>
              </div>
            </template>
            <template #question="{ text }">
              <div class="questionText">{{ text }}</div>
            </template>
            <template #answer="{ text }">
              <div class="questionText">{{ text }}</div>
            </template>
            <template #operation="{ record }">
              <a-button class="mr-20" @click="onEdit(record)">
                <template #icon>
                  <FormOutlined :style="{ fontSize: '12px' }" />
                </template>
              </a-button>
              <a-popconfirm
                title="确定要删除该条记录吗?"
                ok-text="确定"
                cancel-text="取消"
                @confirm="onDelete(record.id)"
                placement="topRight"
              >
                <a-button>
                  <template #icon>
                    <DeleteOutlined :style="{ fontSize: '12px' }" />
                  </template>
                </a-button>
              </a-popconfirm>
            </template>
          </a-table>
        </div>
      </template>
    </template>

    <a-modal
      :visible="modalVisible != ''"
      :title="modalTitle[modalVisible] || ''"
      @ok="modalHandleOk(modalVisible)"
      @cancel="modalVisible = ''"
      width="90%"
      :wrapClassName="
        'wiki-modal-warp' +
        (modalVisible == 'splitText' ? ' split-text-modal' : '')
      "
      :confirm-loading="modalConfirmLoading"
      okText="确认导入"
    >
      <template v-if="modalVisible == 'add' || modalVisible == 'edit'">
        <div class="flex h-full">
          <div class="mr-20 w-full h-full">
            <div class="mb-5">匹配的知识点</div>
            <a-textarea
              v-model:value="model.question"
              style="height: calc(100% - 30px); resize: none"
              placeholder="可以理解为问题。"
              maxlength="3000"
            ></a-textarea>
          </div>
          <div class="h-full w-full mb-5">
            <div class="mb-5">补充知识</div>
            <a-textarea
              v-model:value="model.answer"
              style="height: calc(100% - 30px); resize: none"
              placeholder="可以理解为需要训练的答案。"
              maxlength="3000"
            ></a-textarea>
          </div>
        </div>
      </template>

      <template v-if="modalVisible == 'csvImport'">
        <div class="flex h-full">
          <div style="flex: 2 0 0px" class="mr-20">
            <div class="fs-12">
              <p class="mb-0">
                接受一个 csv 文件，表格头包含 question 和 answer。question
                代表问题，answer 代表答案。
              </p>
              <p>
                导入前会进行去重，如果问题和答案完全相同，则不会被导入，所以最终导入的内容可能会比文件的内容少。但是，对于带有换行的内容，目前无法去重。
              </p>
            </div>
            <h3>请保证 csv 文件为 utf-8 编码</h3>
            <div class="bl-table mt-10">
              <div class="flex bl-table__ll font-bold fs-12">
                <div style="width: 150px" class="bl-table__li">question</div>
                <div style="flex: 1" class="bl-table__li">answer</div>
              </div>
              <div class="flex bl-table__ll fs-12">
                <view style="width: 150px" class="bl-table__li"
                  >如何申明变量？</view
                >
                <view style="flex: 1" class="bl-table__li"
                  >在Python中，可以使用赋值语句来声明变量。例如，将一个整数值赋给变量x可以这样写：x
                  = 42 这样就将整数值42存储在变量x中了。</view
                >
              </div>
              <div class="flex bl-table__ll fs-12">
                <div style="width: 150px" class="bl-table__li">
                  python中的模型、类和函数是什么意思，有什么区别？
                </div>
                <div style="flex: 1" class="bl-table__li">
                  在Python中，模型（Model）、类（Class）和函数（Function）是不同的概念，用于不同的目的。在Python中，模型是解决特定问题的类、函数和变量的集合，类和函数之间的主要区别在于，类是创建对象的蓝图，而函数是执行特定任务的代码块。一个类可以包含多个函数，但一个函数不能包含一个类。模型则是解决特定问题的类、函数和变量的集合。
                </div>
              </div>
            </div>
            <div
              class="mt-10 text-blue cursor-pointer"
              style="text-decoration: underline"
              @click="downloadFile"
            >
              点击下载csv模板
            </div>
            <div class="flex align-center mt-10">
              <a-upload
                accept=".csv"
                :showUploadList="false"
                :before-upload="importCsvBeforeUpload"
                :action="`${baseUrl}/work_ai/user/team/wiki/data/load_csv`"
                @change="importCsvUploadChange"
                name="file"
                :data="{ user_token: utils.getToken() }"
              >
                <a-button
                  :loading="importCsvLoading"
                  type="primary"
                  class="mr-20"
                  >选择 csv 问答对</a-button
                >
              </a-upload>
              <div>一共 {{ importCsvData.length }} 组数据</div>
            </div>
          </div>
          <div
            style="
              flex: 3 0 0px;
              background-color: rgb(0 0 0 / 4%);
              overflow: auto;
            "
            class="p-5 fs-12 h-full"
          >
            <div v-for="(data, index) in importCsvData" :key="index">
              <div>Q{{ index + 1 }}. {{ data.question }}</div>
              <div>A{{ index + 1 }}.{{ data.answer }}</div>
            </div>
          </div>
        </div>
      </template>

      <template v-if="modalVisible == 'splitText'">
        <div class="h-full flex flex-col">
          <div class="fs-12 px-20">
            支持 .txt,.docx,.pdf,.md 文件。AI会自动对文本进行 QA
            拆分，需要较长训练时间。
          </div>
          <div class="fs-12 px-20 mt-10 text-red">
            注意文档中不要放入图片，否则可能导致文件上传失败
          </div>
          <div class="mt-20 px-20 flex align-center">
            <div style="width: 80px">分段模式:</div>
            <div class="flex-1">
              <a-radio-group
                name="radioGroup"
                v-model:value="splitTextModel.mode"
              >
                <a-radio value="subsection">直接分段</a-radio>
                <a-radio value="qa">QA拆分</a-radio>
              </a-radio-group>
            </div>
          </div>
          <div
            class="flex px-20 mt-20 align-center"
            v-if="splitTextModel.mode == 'subsection'"
          >
            <div style="width: 80px">段落长度</div>
            <div class="flex-1">
              <a-slider
                :marks="{
                  300: '300',
                  1000: '1000',
                }"
                :step="50"
                :min="300"
                :max="1000"
                v-model:value="splitTextModel.maxLen"
                :tooltip-visible="true"
                style="width: 300px"
              >
              </a-slider>
            </div>
          </div>
          <div
            class="flex px-20 mt-20 align-center"
            v-if="splitTextModel.mode == 'qa'"
          >
            <div style="width: 80px">下面是</div>
            <div class="flex-1">
              <a-input
                placeholder="搜索相关问题和答案，回车确认"
                v-model:value="splitTextModel.prompt"
              ></a-input>
            </div>
          </div>
          <div
            class="mt-20 px-20 pr-30"
            style="flex: 1 0 0px; height: 0px; overflow-y: auto"
          >
            <div
              class="mb-30"
              v-for="(chunk, index) in splitTextModel.chunks"
              :key="index"
            >
              <div>文本{{ index + 1 }}</div>
              <div class="mt-5">
                <a-textarea
                  v-model:value="splitTextModel.chunks[index]"
                  style="height: 155px"
                  rows="10"
                  placeholder="您可以手动输入，也可以上传文件。文件内容将会解析在此。空内容会自动忽略。"
                ></a-textarea>
              </div>
            </div>
          </div>
        </div>
      </template>
      <template #footer v-if="modalVisible == 'splitText'">
        <div class="flex justify-between">
          <div>
            <a-upload
              accept=".text,.docx,.pdf,.md"
              :showUploadList="false"
              :action="`${baseUrl}/work_ai/user/team/wiki/data/split_load_file`"
              @change="splitTextUploadChange"
              name="file"
              :data="{ user_token: utils.getToken() }"
            >
              <a-button :loading="splitTextLoading" type="primary" class="mr-20"
                >选择文件</a-button
              >
            </a-upload>
          </div>
          <div>
            <a-button @click="modalVisible = ''">取消</a-button>
            <a-button
              :loading="modalConfirmLoading"
              type="primary"
              @click="modalHandleOk(modalVisible)"
              >确认导入</a-button
            >
          </div>
        </div>
      </template>
    </a-modal>
    <AddTeam
      :visible="addTeamVisible"
      @onClose="addTeamVisible = false"
      @success="addTeamSuccess"
    />

    <LoginModal
      :visible="state.loginVisible"
      @onClose="state.loginVisible = false"
      @loginCallback="loginCallback"
    />
  </div>
</template>

<script setup>
import { reactive, ref, watch, inject } from "vue";
import utils from "@/common/utils/utils";
import apiRequest from "@/common/utils/request";
import {
  SyncOutlined,
  QuestionCircleOutlined,
  FormOutlined,
  DeleteOutlined,
  InteractionOutlined,
  PlusCircleOutlined,
  ExclamationCircleOutlined,
  WarningFilled,
  SwapOutlined,
} from "@ant-design/icons-vue";
import { usePagination } from "@/hooks/pagination";
import { useRequest } from "@/hooks/loading";
import defaultSetting from "@/common/utils/defaultSetting";
import { Modal, message } from "ant-design-vue";
import { errorHandler } from "@/common/utils/request";
import store from "@/store";
import AddTeam from "@/components/AddTeam/index.vue";
import { useRoute, useRouter } from "vue-router";

const route = useRoute();
const router = useRouter();

let baseUrl = defaultSetting.requestDomain;

if (process.env.NODE_ENV === "development") {
  baseUrl = baseUrl + "/api";
}

const changeTeamPopoverVisible = inject(["changeTeamPopoverVisible"]);

const columns = [
  {
    dataIndex: "question",
    key: "question",
    slots: { title: "customQuestion", customRender: "question" },
  },
  {
    title: "补充知识",
    dataIndex: "answer",
    key: "answer",
    slots: { customRender: "answer" },
  },
  {
    title: "状态",
    dataIndex: "status_text",
    key: "status_text",
    width: 120,
  },
  {
    title: "操作",
    dataIndex: "operation",
    slots: { customRender: "operation" },
    width: 120,
  },
];

const modalTitle = {
  add: "手动导入数据",
  edit: "更新数据",
  csvImport: "csv 问答对导入",
  splitText: "文件导入",
};

const state = reactive({
  team_id: store.state.user.teamId || "",
  keywords: "",

  loginVisible: false,
  showPage: false,
});

watch(
  () => store.state.user.teamId,
  (teamId) => {
    state.team_id = teamId;

    initData();
  }
);

const visible = ref(false);
const modalVisible = ref("");

const total = ref(0);
const wikiList = ref([]);

const editId = ref(0);
const model = reactive({
  question: "",
  answer: "",
});
const wiki_name = ref(route.query.name);

const { page, pageSize, pagination, onPageChange } = usePagination(
  total,
  10,
  1,
  { simple: true }
);

const { loading, request } = useRequest();

const getWikiList = async () => {
  let params = {
    ...state,
    page: page.value,
    pageSize: pageSize.value,
    wiki_id: route.query.wiki_id,
  };

  const { list, total: totalNum } = await request(
    apiRequest.get("/work_ai", "/user/team/wiki/data", params)
  );

  wikiList.value = list;
  total.value = totalNum;
};

const onAddHandle = () => {
  let params = {
    ...model,
    org_id: utils.getOrgId(),
    team_id: state.team_id,
    wiki_id: route.query.wiki_id,
  };

  modalConfirmLoading.value = true;
  apiRequest
    .post("/work_ai", "/user/team/wiki/data", params)
    .then(() => {
      modalConfirmLoading.value = false;
      modalVisible.value = "";

      page.value = 1;
      getWikiList();
    })
    .catch((err) => {
      modalConfirmLoading.value = false;
    });
};

const onEdit = (record) => {
  editId.value = record.id;
  model.question = record.question;
  model.answer = record.answer;

  modalVisible.value = "edit";
};

const onEditHandle = () => {
  let params = {
    ...model,
    id: editId.value,
    wiki_id: route.query.wiki_id,
  };

  modalConfirmLoading.value = false;

  apiRequest
    .put("/work_ai", "/user/team/wiki/data", params)
    .then(() => {
      modalConfirmLoading.value = false;
      modalVisible.value = "";

      getWikiList();
    })
    .catch((err) => {
      modalConfirmLoading.value = false;
    });
};

watch(modalVisible, (newVisible, oldVisible) => {
  if (newVisible == "" && (oldVisible == "add" || oldVisible == "edit")) {
    model.question = "";
    model.answer = "";
  }

  if (newVisible == "" && oldVisible == "edit") {
    editId.value = 0;
  }

  if (newVisible == "" && oldVisible == "csvImport") {
    importCsvData.value = [];
    uploadCsvFile.value = null;
  }

  if (newVisible == "" && oldVisible == "splitText") {
    splitTextModel.mode = "subsection";
    splitTextModel.prompt = "";
    splitTextModel.chunks = [""];
  }

  if (newVisible) {
    visible.value = false;
  }
});

const onDelete = async (id) => {
  apiRequest
    .del("/work_ai", "/user/team/wiki/data", { id })
    .then(getWikiList)
    .catch((err) => {});
};

const modalConfirmLoading = ref(false);

const modalHandleOk = (type) => {
  if (type == "add") {
    onAddHandle();
  } else if (type == "edit") {
    onEditHandle();
  } else if (type == "csvImport") {
    onCsvImportHandle();
  } else if (type == "splitText") {
    onSplitTextHandle();
  }
};

const importCsvLoading = ref(false);
const uploadCsvFile = ref(null);
const importCsvData = ref([]);

const importCsvBeforeUpload = (file) => {
  uploadCsvFile.value = file;
};

const uploadResponse = (response) => {
  const { code } = response;

  if (code === 1000) {
    return Promise.resolve(response.data);
  } else {
    return errorHandler({ data: response });
  }
};

const importCsvUploadChange = ({ file }) => {
  if (file.status === "uploading") {
    importCsvLoading.value = true;
    return;
  }

  if (file.status === "done") {
    importCsvLoading.value = false;

    uploadResponse(file.response).then(({ data }) => {
      importCsvData.value = data;
    });
  }

  if (file.status === "error") {
    importCsvLoading.value = false;
    uploadCsvFile.value = null;

    message.error("上传失败");
  }
};

const onCsvImportHandle = () => {
  if (!uploadCsvFile.value) {
    return;
  }

  Modal.confirm({
    title: "提示",
    content: "确认导入该数据集?",
    okText: "确认",
    cancelText: "取消",
    onOk() {
      modalConfirmLoading.value = true;

      const data = {
        org_id: utils.getOrgId(),
        team_id: state.team_id,
        file: uploadCsvFile.value,
        user_token: utils.getToken(),
        wiki_id: route.query.wiki_id,
      };

      apiRequest
        .upload("/work_ai", "/user/team/wiki/data/import_csv", data)
        .then(({ data: { count } }) => {
          message.success(
            `导入数据成功，最终导入: ${count} 条数据。需要一段时间训练`
          );

          modalConfirmLoading.value = false;
          modalVisible.value = "";

          page.value = 1;
          getWikiList();
        })
        .catch((err) => {
          modalConfirmLoading.value = false;
        });
    },
  });
};

const splitTextLoading = ref(false);
const splitTextModel = reactive({
  mode: "subsection",
  prompt: "",
  chunks: [""],
  maxLen: 600,
});

const splitTextUploadChange = ({ file }) => {
  if (file.status === "uploading") {
    splitTextLoading.value = true;
    return;
  }

  if (file.status === "done") {
    splitTextLoading.value = false;

    uploadResponse(file.response).then(({ data }) => {
      splitTextModel.chunks = [data].concat(splitTextModel.chunks);
    });
  }

  if (file.status === "error") {
    splitTextLoading.value = false;
    message.error("上传失败");
  }
};

const onSplitTextHandle = () => {
  const splitRes = splitTextModel.chunks.filter((item) => item);

  if (splitRes.length == 0) {
    return;
  }

  Modal.confirm({
    title: "提示",
    content: `确认导入该文件，需要一定时间进行拆解，该任务无法终止。一共${splitRes.length}组`,
    okText: "确认",
    cancelText: "取消",
    onOk() {
      modalConfirmLoading.value = true;

      const data = {
        org_id: utils.getOrgId(),
        chunks: splitRes,
        team_id: state.team_id,
        mode: splitTextModel.mode,
        prompt: `下面是"${splitTextModel.prompt || "一段长文本"}"`,
        wiki_id: route.query.wiki_id,
        maxLen: splitTextModel.maxLen,
      };

      apiRequest
        .post("/work_ai", "/user/team/wiki/data/split_text", data)
        .then((res) => {
          message.success(`导入数据成功,需要一段拆解和训练`);

          modalConfirmLoading.value = false;
          modalVisible.value = "";

          page.value = 1;
          getWikiList();
        })
        .catch((err) => {
          console.log(err);
          modalConfirmLoading.value = false;
        });
    },
  });
};

//下载文件
const downloadFile = () => {
  const filename = "templates.csv";
  const fileUrl = `${baseUrl}/public_web/static/file/org/template.csv`;
  const link = document.createElement("a");
  link.style.display = "none";
  link.href = fileUrl;
  link.setAttribute("download", filename);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
};

const initData = async () => {
  page.value = 1;
  wikiList.value = [];
  total.value = 0;

  if (state.team_id) {
    await getWikiList();
  }
};

const handleTableChange = ({ current, pageSize }) => {
  onPageChange(current, pageSize);
  getWikiList();
};

const addTeamVisible = ref(false);

const addTeamSuccess = () => {
  addTeamVisible.value = false;
  initData();
};

utils.checkLogin().then((isLogin) => {
  if (!isLogin) {
    state.loginVisible = true;
    return;
  }
  state.showPage = true;
  initData();
});

const loginCallback = () => {
  state.loginVisible = false;
  router.go(0);
};
</script>

<style lang="less" scoped>
.pagewarp {
  padding: 20px;
}

.bl-table {
  border-radius: 4px;
  border: 1px solid #9a9a9a;

  &__ll {
    line-height: 30px;
  }

  &__ll:last-child .bl-table__li {
    border-bottom: none;
  }

  &__ll .bl-table__li:last-child {
    border-right: none;
  }

  &__li {
    padding: 0px 7px;
    border-right: 1px solid #9a9a9a;
    border-bottom: 1px solid #9a9a9a;
  }
}

.questionText {
  min-width: 150px;
  max-width: 500px;
  max-height: 250px;
  white-space: pre-wrap;
  overflow-y: auto;
}
</style>

<style lang="less">
.wiki-modal-warp {
  display: flex;
  justify-content: center;
  align-items: center;

  .ant-modal {
    height: 90vh;
    top: 0px;
    padding-bottom: 0px;

    .ant-modal-content {
      height: 100%;
      display: flex;
      flex-direction: column;

      .ant-modal-header {
        flex: 0 1 0%;
      }

      .ant-modal-body {
        flex: 1 0 0px;
        overflow: hidden;
      }
    }
  }
}

.split-text-modal {
  .ant-modal-body {
    padding: 20px 0px;
  }
}
</style>
